/*
 * WeatherUserModelImpl
 * 
 * Copyright 2008-2009 Centro Andaluz de Innovación y Tecnologías de la
 * Información y las Comunicaciones (CITIC). All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 *
 * Please contact CITIC - Edificio CITIC, C/ Marie Curie, 6 Parque
 * Tecnológico de Andalucía 29590 - Campanillas, Málaga, Spain
 * or visit www.citic.es, if you need additional information or
 * have any questions.
 */

package es.citic.puedes.weatherservice.impl.umm;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.persistence.EntityManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import es.citic.puedes.weatherservice.WeatherException;
import es.citic.puedes.weatherservice.impl.bbdd.WeatherDataBase;
import es.citic.puedes.weatherservice.impl.tables.WeatherLocation;
import es.citic.puedes.weatherservice.impl.tables.WeatherUserModel;
import es.citic.puedes.weatherservice.model.Language;
import es.citic.puedes.weatherservice.umm.IWeatherUserModel;
import es.citic.puedes.weatherservice.umm.WeatherPreferences;
import es.citic.puedes.weatherservice.utils.Utils;

public class WeatherUserModelImpl implements IWeatherUserModel {
	private Integer userId;
	List<WeatherUserModel> userModel = new ArrayList<WeatherUserModel>();
	public static Logger logger = LoggerFactory
			.getLogger(WeatherUserModelImpl.class);

	private WeatherDataBase wdb;

	/**
	 * Constructor
	 * 
	 * @param userId
	 *            User id
	 * @throws WeatherException
	 *             If an exception occurred
	 */
	public WeatherUserModelImpl(Integer userId, WeatherDataBase wdb)
			throws WeatherException {
		this.userId = userId;
		this.wdb = wdb;
		logger.debug("Enter : WeatherUserModelImpl(" + userId + ")");
		// Select all WeatherUserModel from userId
		EntityManager em = wdb.getEntityManager();
		userModel = wdb.selectWeatherUserModelQuery(em, userId);
		wdb.closeEntityManager(em);
		logger.debug("Exit :WeatherUserModelImpl");
	}

	@Override
	public List<WeatherPreferences> getPreferences(Language language)
			throws WeatherException {

		List<WeatherUserModel> userModelList = null;
		List<WeatherPreferences> preferences = new ArrayList<WeatherPreferences>();

		logger.debug("Enter : getPreferences()");

		EntityManager em = wdb.getEntityManager();
		// Select all WeatherUserModel from userId
		userModelList = wdb.selectWeatherUserModelQuery(em, userId);
		if (userModelList != null) {

			// Set each WeatherUserModel element in a WeatherPreferences and add
			// them in a list
			for (int i = 0; i < userModelList.size(); i++) {
				WeatherUserModel userModel = userModelList.get(i);
				WeatherLocation weatherLocation = userModel
						.getWeatherlocation();
				WeatherPreferences weatherPreferences = new WeatherPreferences(
						userId, weatherLocation.getLocation(),
						weatherLocation.getCountry());
				weatherPreferences.setValue(userModel.getValue());

				// modification cause: set the date for the chosen language
				String stringDate = Utils.convertDateToStringLanguageDate(
						userModel.getDate(), language);
				// weatherPreferences.setDate(userModel.getDate().toString().substring(0,
				// 10));
				weatherPreferences.setDate(stringDate);

				preferences.add(weatherPreferences);
			}
		}

		// Normalize WeatherPreferences list
		preferences = normalizeList(preferences);
		// Order WeatherPreferences list by descendant value parameter
		preferences = orderList(preferences);
		wdb.closeEntityManager(em);

		logger.debug("Exit : getPreferences()");

		return preferences;
	}

	@Override
	public void saveUserModel() throws WeatherException {
		logger.debug("Enter : saveUserModel()");
		if (userModel != null) {
			EntityManager em = null;
			em = wdb.getEntityManager();
			em.getTransaction().begin();
			// Save each WeatherUserModel form user in BBDD
			for (int i = 0; i < userModel.size(); i++) {
				em.merge(userModel.get(i));
			}
			em.getTransaction().commit();
			wdb.closeEntityManager(em);
			logger.debug("Exit : saveUserModel()");
		}
	}

	
	public void setPreferences(WeatherPreferences preferences) {
		logger.debug("Enter : setPreferences");
		WeatherUserModel userModelFound = null;
		int pos = 0;
		EntityManager em = null;
		WeatherLocation locationDDBB = null;
		try {
			em = wdb.getEntityManager();
			locationDDBB = wdb.selectWeatherLocationQuery(em,
					preferences.getLocation(), preferences.getCountry());
			if (locationDDBB != null) {
				if (userModel != null) {
					// Search if user has this preferences yet
					for (int i = 0; i < userModel.size(); i++) {
						WeatherUserModel model = userModel.get(i);
						WeatherLocation weatherLocation = model
								.getWeatherlocation();
						if (weatherLocation.getCountry().equals(
								preferences.getCountry())
								&& (weatherLocation.getLocation()
										.equals(preferences.getLocation()))) {
							userModelFound = model;
							pos = i;
						}
					}
					if (userModelFound == null) {
						userModel.add(createWeatherUserModel(locationDDBB));
	
					} else {
						// modification cause: adds the date to the preference
						// weather user model modified
						userModelFound.setValue(userModelFound.getValue() + 1);
						userModelFound.setDate(Calendar.getInstance().getTime());
						userModel.set(pos, userModelFound);
	
					}
				} else {
					userModel.add(createWeatherUserModel(locationDDBB));
				}
			} else {
				userModel.add(createWeatherUserModel(preferences.getLocation(),
						preferences.getCountry()));
			}

		} catch (WeatherException e) {
			userModel.add(createWeatherUserModel(preferences.getLocation(),
					preferences.getCountry()));

		}
		wdb.closeEntityManager(em);
		logger.debug("Exit : setPreferences");
	}

	/**
	 * Create a new WeatherUserModel
	 * 
	 * @param WeatherLocation
	 *            locationDDBB
	 * @return new WeatherUserModel
	 * 
	 * 
	 */

	// modification cause: adds the date to the preference weather user model
	private WeatherUserModel createWeatherUserModel(WeatherLocation locationDDBB) {
		logger.debug("Enter : createWeatherUserModel");

		WeatherUserModel newUserModel = new WeatherUserModel(1, locationDDBB,
				userId, Calendar.getInstance().getTime());
		logger.debug("Exit : createWeatherUserModel");
		return newUserModel;
	}

	// modification cause: adds the date to the preference weather user model
	private WeatherUserModel createWeatherUserModel(String location,
			String country) {
		logger.debug("Enter : createWeatherUserModel");
		WeatherLocation newWeatherLocation = new WeatherLocation(location,
				country);

		WeatherUserModel newUserModel = new WeatherUserModel(1,
				newWeatherLocation, userId, Calendar.getInstance().getTime());
		logger.debug("Exit : createWeatherUserModel");
		return newUserModel;
	}

	/**
	 * Normalize value parameter for each WeatherPreferences
	 * 
	 * @param preferenceList
	 *            list to normalize
	 * @return normalizaPreferenceList weather preference list normalize
	 */
	private List<WeatherPreferences> normalizeList(
			List<WeatherPreferences> preferenceList) {
		logger.debug("Enter : normalizeList");
		List<WeatherPreferences> normalizaPreferenceList = new ArrayList<WeatherPreferences>();
		if (!preferenceList.isEmpty()) {

			int totalEntries = preferenceList.size();
			double currentPreferenceCount = 0.0;
			double currentPreferenceValue = 0.0;
			double currentTotalRestCount = 0.0;

			for (int i = 0; i < totalEntries; i++) {
				currentTotalRestCount = 0.0;
				WeatherPreferences currentPreference = preferenceList.get(i);

				// gets the value of the current preference
				currentPreferenceCount = preferenceList.get(i).getValue();

				// calculates the sum of the preferences
				for (int j = 0; j < totalEntries; j++) {
					currentTotalRestCount = currentTotalRestCount
							+ preferenceList.get(j).getValue();
				}

				// calculates the normalized value for the current preference
				// using the sum of preferences
				currentTotalRestCount = Math.abs(currentTotalRestCount);
				currentPreferenceValue = currentPreferenceCount
						/ (currentTotalRestCount / 100);

				// creates and adds the normalized preference to a set
				WeatherPreferences p = new WeatherPreferences(userId,
						currentPreference.getLocation(),
						currentPreference.getCountry());
				Double doubleValue = new Double(currentPreferenceValue);
				p.setValue(doubleValue.intValue());
				p.setDate(currentPreference.getDate());
				normalizaPreferenceList.add(p);
			}
		}
		logger.debug("Exit : normalizeList");
		return normalizaPreferenceList;
	}

	/**
	 * Order List WeatherPreferences descendant by value
	 * 
	 * @param preferenceList
	 *            list to order by value parameter
	 * @return orderPreferenceList order list with preferences user
	 */
	private List<WeatherPreferences> orderList(
			List<WeatherPreferences> preferenceList) {
		logger.debug("Enter : orderList");
		List<WeatherPreferences> orderPreferenceList = new ArrayList<WeatherPreferences>();
		if (!preferenceList.isEmpty()) {
			orderPreferenceList.add(preferenceList.get(0));
			preferenceList.remove(0);
			int i = 0;
			// Order descendant list by value parameter
			while (!preferenceList.isEmpty()) {
				WeatherPreferences preference = preferenceList.get(0);
				if (i == orderPreferenceList.size()) {
					orderPreferenceList.add(i, preference);
					preferenceList.remove(0);
				} else {
					WeatherPreferences orderPreference = orderPreferenceList
							.get(i);
					if (orderPreference.getValue() <= preference.getValue()) {
						orderPreferenceList.add(i, preference);
						preferenceList.remove(0);
						i = 0;
					} else {
						i++;
					}
				}

			}
		}
		logger.debug("Exit : orderList");
		return orderPreferenceList;
	}

}